// Copyright (C) 2010  Andrew H. Chan
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

#include "input_parser.h"

using namespace std;

InputParser::InputParser() {} // Default constructor

int InputParser::parse(string file_name) {
    string line;
    ifstream fileH(file_name.c_str());
    if(fileH.is_open()) {
        // NOTE: We deduce the number of loci from the number of PIM vectors
        // Get mutation rate
        getline(fileH, line);
        if(fileH.eof()) {
            cout << "Parse error: Mutation rate not found." << endl;;
            return 1;
        }
        boost::algorithm::trim(line);
        istringstream input_stream(line);
        if(!(input_stream >> mut)) {
            throw runtime_error("InputParser::parse() : Could not convert mutation rate to double."); 
        }
        // Get recombination rate 
        getline(fileH, line);
        if(fileH.eof()) {
            cout << "Parse error: Recombination rate not found." << endl;;
            return 1;
        }
        boost::algorithm::trim(line);
        input_stream.str(line);
        input_stream.clear();
        if(!(input_stream >> rho)) {
            throw runtime_error("InputParser::parse() : Could not convert recombination rate to double."); 
        }
        // Check for PIM vectors
        getline(fileH, line);
        if(fileH.eof()) {
            cout << "Parse error while parsing PIM vectors. EOF after recombination rate." << endl;;
            return 1;
        }
        boost::algorithm::trim(line);
        // Get PIM vectors 
        if(line == "PIM") {
            while(!fileH.eof()) {
                getline(fileH, line);
                if(fileH.eof()) {
                    cout << "Parse error while parsing PIM vectors. Need a line with the word 'PIM' to separate recombination rate from PIM vectors." << endl;;
                    return 1;
                }
                boost::algorithm::trim(line);
                if(line == "SAMPLE") {
                    break; // Break and parse sample
                }
                pim_vectors.push_back(vd());
                input_stream.str(line);
                input_stream.clear();
                while(!input_stream.eof()) {
                    double pim_value;
                    if(!(input_stream >> pim_value)) {
                        throw runtime_error("InputParser::parse() : Could not convert PIM value to double.");
                    }
                    pim_vectors.back().push_back(pim_value);
                }
            }
        }
        else {
            cout << "Parse error while parsing PIM vectors." << endl;
            return 1;
        }

        // Deduce the number of loci from the number of PIM vectors
        num_loci = pim_vectors.size();

        // Ensure that every loci has the same number of alleles by checking pim_vectors
        num_alleles = pim_vectors.front().size();
        for(vd2_iter iter = (++pim_vectors.begin()); iter != pim_vectors.end();
                ++iter) {
            if(iter->size() != num_alleles) {
                cout << "Error: All loci must have same number of alleles." << endl;
                return 1;
            }
        }

        // Parse the samples
        if(line == "SAMPLE") {
            while(!fileH.eof()) {
                getline(fileH, line);
                if(fileH.eof()) {
                    break;
                }
                boost::algorithm::trim(line);
                input_stream.str(line);
                input_stream.clear();
                individuals.push_back( pair< vi, int > ( vi(), 0 ) ); 
                // mutation_type = allele type
                int mutation_type;
                while(!input_stream.eof()) {
                    if(!(input_stream >> mutation_type)) {
                        throw runtime_error("InputParser::parse() : Could not convert allele type (or quantity) to integer.");
                    }
                    // if input_stream.eof() is true, then mutation_type contains the last value in the line for the haplotype, which is the quantity for that haplotype. Don't add it to the list of alleles for the haplotype. Instead, break from the loop and assign it to the quantity for that haplotype. 
                    if(input_stream.eof()) {
                        break;
                    }
                    // Make sure mutation_type is valid
                    if(mutation_type >= static_cast<int>(num_alleles) || mutation_type < -1) {
                        throw runtime_error("InputParser::parse() : Allele type in sample is invalid. Mutation type must be between -1 and the number of alleles (determined by the length of the PIM vectors), where -1 denotes an unspecified allele.");
                    }
                    individuals.back().first.push_back(mutation_type);
                }
                // Assign last value on line to quantity
                individuals.back().second = mutation_type; 
                
                // Make sure that number of alleles defined for haplotype is equal to the number of loci
                if(individuals.back().first.size() != num_loci) {
                    throw runtime_error("InputParser::parse() : Incorrect number of alleles specified for haplotype. The number of alleles specified for a haplotype must be equal to the number of loci (one allele per locus), which is deduced from the number of PIM vectors.");
                }
            }
        }
        else {
            cout << "Parse error while parsing sample list. Need a line with the word 'SAMPLE' to separate PIM vectors from list of samples." << endl;
            return 1;
        }
    }
    else {
        cout << "Error: Unable to open file " << file_name << endl;
        return 1;
    }

    return 0;
}

int InputParser::renormalize_PIM() {
    for(vd2_iter outer_iter = pim_vectors.begin(); outer_iter != pim_vectors.end(); ++outer_iter) {
        double sum = 0;
        for(vd_iter inner_iter = outer_iter->begin(); inner_iter != outer_iter->end(); ++inner_iter) {
            sum += *inner_iter;
        }
        for(vd_iter inner_iter = outer_iter->begin(); inner_iter != outer_iter->end(); ++inner_iter) {
            *inner_iter /= sum;
        }
    }
    return 0;
}
